/// <reference path="./Sets.ts" />
/// <reference path="./Pool.ts" />
/// <reference path="./LoadDir.ts" />

namespace apeng {

    export class Queue {

        public static readonly pool = new PoolOnce(100, () => new Queue(), (data) => data.dispose())

        private loadDir = new LoadDir(0, null!)

        private values: ((complele: () => void) => void)[] = []
        private _values: ((complele: () => void) => void)[] = []

        public isRun: boolean = false

        constructor(
            public complete: () => void = null!,
            public interval: number = -1,
            public log: string | ((index: number) => string) = "",
        ) { }

        public add(cb: (complete: () => void) => void, run = false) {
            this.values.push(cb)
            if (run)
                this._values.push(cb)
            return this
        }

        public remove(index: number) {
            let value = this.values[index]
            if (value) {
                Sets.delete(this._values, value)
                this.values[index] = null!
            }
        }

        public remove2(cb: Function) {
            let index = this.values.indexOf(cb as any)
            if (index != -1)
                this.remove(index)
        }

        public has(index: number) {
            return !!this.values[index]
        }

        public runIndex(index: number, complete: () => void = () => { }) {
            let value = this.values[index]
            if (value) {
                value(complete)
                this.remove(index)
            }
        }

        /**
         * 开始运行
         * @param count 并发个数
         * @returns 
         */
        public run(count = 1) {
            if (!this.isRun) {
                this._values.length = 0
                for (let value of this.values)
                    if (value)
                        this._values.push(value)
            }
            this.isRun = true
            let value = this._values.splice(0, count)
            if (value.length == 0) {
                this.isRun = false
                if (this.complete)
                    this.complete()
                return
            }

            if (this.log) {
                if (typeof this.log == "function")
                    console.log("Queue run " + this.log(this.values.length - this._values.length - 1))
                else
                    console.log("Queue run " + this.log, this.values.length - this._values.length)
            }

            let complete = () => {
                if (this.interval != 0) 
                    setTimeout(this.run.bind(this, count), this.interval * 1000)
                else
                    this.run(count)
            }
            if (count == 1)
                value[0](complete)
            else {
                this.loadDir.onFinish = complete
                this.loadDir.count = value.length
                for (let _value of value)
                    _value(this.loadDir.subCount())
            }
        }

        public clear() {
            // TimerMgr.clearAll(this)
            this.values.length = 0
        }

        public dispose() {
            this.clear()
            this.complete = null!
            this.interval = -1
            this.isRun = false
            this.log = ""
        }

    }
}